#include "gamewindow.h"
#include "gameclient.h"

#include "cardset.h"

#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPaintEvent>
#include <QCloseEvent>
#include <QJsonArray>
#include <QPainter>
#include <QPoint>
#include <QRect>
#include <QPen>

GameWindow::GameWindow(GameClient* clientPtr, QWidget *parent) : QWidget(parent),
    client(clientPtr)
{
    setFixedSize(800, 600);
    setWindowTitle("斗地主");
    initUi();
    initConnections();
}

void GameWindow::initUi()
{
    btnYes = new QPushButton;
    btnNo = new QPushButton;
    btnYes->setText("yes");
    btnNo->setText("no");
    btnYes->setEnabled(false);
    btnNo->setEnabled(false);

    QHBoxLayout *buttons = new QHBoxLayout;
    buttons->addWidget(btnYes);
    buttons->addWidget(btnNo);
    buttons->setAlignment(Qt::AlignBottom);

    QVBoxLayout *layout = new QVBoxLayout(this);
    layout->addStretch();
    layout->addLayout(buttons);
}

void GameWindow::initConnections()
{
    connect(client, &GameClient::clientStateChanged, this, &GameWindow::onClientStateChanged);
    connect(client, &GameClient::clientUpdated, this, &GameWindow::onclientUpdated);
    connect(client, &GameClient::cardsPosted, this, &GameWindow::onCardsPosted);
}

static inline QRect getPlayerRect(int player)
{
    int w = GameWindow::cardWidth, h = GameWindow::cardHeight;
    if (player == 1)
        return QRect(20, 100, w, h);
    return QRect(800 - 20 - w, 100, w, h);
}

void GameWindow::getActionsText(QString act[])
{
    QJsonArray pa = client->go["preempt"].toArray();
    int pv[3];
    for (int i = 0; i < client->numPlayers; ++i)
        pv[i] = pa[i].toInt();

    if (pv[0] > 0) {
        act[0] = "叫";
        if (pv[1] > 0) {
            act[1] = "抢";
        } else if (pv[1] == 0) {
            act[1] = "不抢";
        }
        if (pv[2] > 0)
            act[2] = "抢";
        else if (pv[2] == 0)
            act[2] = "不抢";
    } else if (pv[0] == 0) {
        act[0] = "不叫";
        if (pv[1] > 0) {
            act[1] = "叫";
            if (pv[2] > 0)
                act[2] = "抢";
            else if (pv[2] == 0)
                act[2] = "不抢";
        } else if (pv[1] == 0) {
            act[1] = "不叫";
            if (pv[2] > 0)
                act[2] = "叫";
            else if (pv[2] == 0)
                act[2] = "不叫";
        }
    }
}

void GameWindow::drawPlayerStates(QPainter& p)
{
    if (!client->dataReady)
        return;

    const QJsonObject &o = client->go;
    int thisId = o["id"].toInt();
    int landlord = o["landlord"].toInt();
    QJsonArray posted = o["posted"].toArray();
    QJsonArray counts = o["count"].toArray();

    QString act[3];
    if (client->state == GameState::preempting)
        getActionsText(act);

    int playerNum = 0;
    for (int i = 0; i < client->numPlayers; ++i) {
        QRect rect = (i == thisId) ?
            QRect(800 - 20 - cardWidth, 400, cardWidth, cardHeight) : getPlayerRect(playerNum++);
        QString desc = "玩家" + QString::number(i) + "\n";
        if (landlord == -1) // landlord not determined
            desc += act[i];
        else {
            desc += (i == landlord) ? "地主" : "农民";
            int numCards = counts[i].toInt();
            if (client->winner == i) // game is over
                numCards = 0;
            desc += "\n" + QString::number(numCards);

            if (client->state == GameState::over)
                desc += QString("\n") + (client->judgeWinner(i) ? "胜利" : "失败");
            else if (client->state == GameState::started && !posted[i].toInt())
                desc += "\n不出";
        }

        p.drawRect(rect);
        p.drawText(rect, desc);
    }
}

void GameWindow::drawCards(QPainter &p)
{
    if (!client->dataReady)
        return;

    QString rcardsRepr = client->go["rcards"].toString();
    QString pcardsRepr = client->go["pcards"].toString();

    QBrush brushSel(Qt::yellow), brush(Qt::gray);

    // hand cards
    QPoint base(handCardsAreaX, handCardsAreaY);
    for (int i = 0; i < client->handCards.size(); ++i) {
        Card card = client->handCards[i];
        int x = base.x() + 30 * i;
        int y = base.y();
        QRect r(x, y, cardWidth, cardHeight);
        p.setBrush(client->selected[i] ? brushSel : brush);
        p.drawRect(r);
        p.drawText(r, card.name());
    }

    // posted cards
    p.setBrush(brush);
    base = QPoint(100, 200);
    base.rx() += client->go["last"].toInt() * 50;
    for (int i = 0; i < pcardsRepr.size(); ++i) {
        Card card = Card::fromChar(pcardsRepr[i].unicode());
        int x = base.x() + 30 * i;
        int y = base.y();
        QRect r(x, y, cardWidth, cardHeight);
        p.drawRect(r);
        p.drawText(r, card.name());
    }
    QString text = CardSet(pcardsRepr).getType();
    if (text != "无效")
        p.drawText(QRect(400, 160, 40, 20), text);

    int landlord = client->go["landlord"].toInt();

    // cards * 3
    base = QPoint(300, 40);
    for (int i = 0; i < rcardsRepr.size(); ++i) {
        Card card = Card::fromChar(rcardsRepr[i].unicode());
        int x = base.x() + 80 * i;
        int y = base.y();
        QRect r(x, y, cardWidth, cardHeight);
        p.drawRect(r);
        if (landlord != -1)
            p.drawText(r, card.name());
    }
}

void GameWindow::drawPrompt(QPainter& p)
{
    QRect rect(360, 320, 100, 20);
    if (client->state == GameState::waiting || client->state == GameState::preempting)
        p.drawText(rect, "等待中...");
    if (client->postIllegal)
        p.drawText(rect, "出牌不合法");
    if (client->state == GameState::over)
        p.drawText(rect, client->judgeWinner() ? "你赢了" : "你输了");
}

void GameWindow::paintEvent(QPaintEvent* e)
{
    Q_UNUSED(e);

    QPainter p(this);

    drawPlayerStates(p);
    drawCards(p);
    drawPrompt(p);
}

void GameWindow::disableButtons()
{
    btnYes->disconnect();
    btnNo->disconnect();
    btnYes->setEnabled(false);
    btnNo->setEnabled(false);
}

void GameWindow::setButtons()
{
    switch (client->state) {
    case GameState::preempting: {
        bool isFirst = true;
        int thisId = client->go["id"].toInt();
        QJsonArray pv = client->go["preempt"].toArray();
        for (int i = 0; i < thisId; ++i)
            if (pv[i].toInt() > 0)
                isFirst = false;
        QString ch = isFirst ? "叫" : "抢";
        btnYes->setText(ch);
        btnNo->setText("不" + ch);
        btnYes->setEnabled(true);
        btnNo->setEnabled(true);
        connect(btnYes, &QPushButton::clicked, [this](){
            client->doPreempt(true);
            disableButtons();
        });
        connect(btnNo, &QPushButton::clicked, [this](){
            client->doPreempt(false);
            disableButtons();
        });
        break;
    }
    case GameState::started: {
        btnYes->setText("出牌");
        btnNo->setText("不出");
        btnYes->setEnabled(true);
        btnNo->setEnabled(!client->mustPost);
        connect(btnYes, &QPushButton::clicked, [this](){ client->postCards(false); });
        connect(btnNo, &QPushButton::clicked, [this](){ client->postCards(true); });
        break;
    }
    case GameState::over: {
        btnYes->setText("重新开始");
        btnNo->setText("结束游戏");
        btnYes->setEnabled(true);
        btnNo->setEnabled(true);
        connect(btnYes, &QPushButton::clicked, [this](){
            client->restartGame();
            disableButtons();
        });
        connect(btnNo, &QPushButton::clicked, this, &GameWindow::close);
        break;
    }
    default:
        break;
    }
}

void GameWindow::mousePressEvent(QMouseEvent* e)
{
    Q_UNUSED(e);

    int x = e->x(), y = e->y();
    // qDebug("[W] mouse (%d, %d)", x, y);

    if (!client->dataReady)
        return;
    if (x < handCardsAreaX || y <= handCardsAreaY || y >= handCardsAreaY + cardHeight)
        return;
    int blockId = (x - handCardsAreaX) / 30;
    int numCards = client->go["hcards"].toString().size();
    if (blockId == numCards)
        blockId--;
    if (0 <= blockId && blockId < numCards) {
        bool value = client->selected[blockId];
        client->selected[blockId] = !value;
        update();
    }
}

void GameWindow::closeEvent(QCloseEvent* e)
{
    Q_UNUSED(e);
}

void GameWindow::onclientUpdated()
{
    update();
}

void GameWindow::onClientStateChanged()
{
    setButtons();
    update();
}

void GameWindow::onCardsPosted(bool success)
{
    if (success)
        disableButtons();
    update();
}
